#include "quad.h"

/* 
 * Créer une liste vide 
 */
list_quad* creer_list_vide() {
	list_quad* lq = malloc(sizeof(list_quad));
	return lq;
}

/* 
 * Créer une liste initialisé avec un quad 
 */
list_quad* creer_list(quad* q) {
	list_quad* lq = malloc(sizeof(list_quad));
	lq->q = q;
	return lq;
}

/*
 * Récupérer le dernier résultat de la liste de quads
 */
symbol_table* get_list_res(list_quad* l) {
	while(l->next != NULL) l = l->next;
	return l->q->res;
}

/* 
 * Concatène l2 dans l1 
 */
list_quad* concat(list_quad** l1, list_quad** l2) {
	if(*l2 == NULL) return *l1;
	list_quad* courrant = *l1;
	if(*l1 == NULL) {
		 *l1 = *l2;
		 return *l1;
	}
	while(courrant->next != NULL ) courrant = courrant->next;
	courrant->next = *l2;	
	return *l1;
}

/* 
 * Complete la liste de quad l avec l'adresse next_quad 
 */ 
void complete(list_quad** l,int next_quad) {
	list_quad* courrant = *l;
	while(courrant != NULL) {
		// Si on a un  GOTO ? 
		if ((courrant->q->operateur == OP_EQUAL
		     || courrant->q->operateur == OP_INF
		     || courrant->q->operateur == OP_INF_EQUAL
		     || courrant->q->operateur == OP_SUP
		     || courrant->q->operateur == OP_SUP_EQUAL		
		     || courrant->q->operateur == OP_GOTO
		     || courrant->q->operateur == OP_NEQUAL)
		    && courrant->q->next == -1) courrant->q->next = next_quad;
		courrant = courrant->next;
	}
}

/*  
 * Affichage d'un quad 
 */
void print_quad(quad* qd){
	if(qd->operateur == OP_EQUAL) printf("%d if %s == %s GOTO %d\n",qd->label,qd->arg1->nom,qd->arg2->nom,qd->next);
	else if(qd->operateur == OP_NEQUAL) printf("%d if %s != %s GOTO %d\n",qd->label,qd->arg1->nom,qd->arg2->nom,qd->next);
	else if(qd->operateur == OP_INF) printf("%d if %s < %s GOTO %d\n",qd->label,qd->arg1->nom,qd->arg2->nom,qd->next);
	else if(qd->operateur == OP_INF_EQUAL) printf("%d if %s <= %s GOTO %d\n",qd->label,qd->arg1->nom,qd->arg2->nom,qd->next);
	else if(qd->operateur == OP_SUP) printf("%d if %s > %s GOTO %d\n",qd->label,qd->arg1->nom,qd->arg2->nom,qd->next);
	else if(qd->operateur == OP_SUP_EQUAL) printf("%d if %s >= %s GOTO %d\n",qd->label,qd->arg1->nom,qd->arg2->nom,qd->next);
	else if(qd->operateur == OP_GOTO) printf("%d GOTO %d\n",qd->label,qd->next);
	else if(qd->operateur == OP_ASSIGN) printf("%d %s = %s\n",qd->label,qd->res->nom,qd->arg1->nom);
	else if(qd->operateur == OP_ASSIGN_ADR) printf("%d %s = & %s\n",qd->label,qd->res->nom,qd->arg1->nom);
        else if(qd->operateur == OP_ASSIGN_PTR) printf("%d * %s = %s\n",qd->label,qd->res->nom,qd->arg1->nom);
	else if(qd->operateur == OP_ASSIGN_VAL) printf("%d %s = * %s\n",qd->label,qd->res->nom,qd->arg1->nom);
	else if(qd->operateur == OP_ADD) printf("%d %s = %s + %s\n",qd->label,qd->res->nom,qd->arg1->nom,qd->arg2->nom);
	else if(qd->operateur == OP_SUB) printf("%d %s = %s - %s\n",qd->label,qd->res->nom,qd->arg1->nom,qd->arg2->nom);
	else if(qd->operateur == OP_MUL) printf("%d %s = %s * %s\n",qd->label,qd->res->nom,qd->arg1->nom,qd->arg2->nom);
	else if(qd->operateur == OP_DIV) printf("%d %s = %s / %s\n",qd->label,qd->res->nom,qd->arg1->nom,qd->arg2->nom);
	else if(qd->operateur == OP_ABS) printf("%d %s = abs( %s )\n",qd->label,qd->res->nom,qd->arg1->nom);
	else if(qd->operateur == OP_PRINT_DIGIT) printf("%d Afficher entier : %s\n",qd->label,qd->arg1->nom);
	else if(qd->operateur == OP_PRINT_STRING) printf("%d Afficher chaine : %s\n",qd->label,qd->arg1->nom);
	else if(qd->operateur == LABEL_END) printf("%d END\n",qd->label);
}

/* 
 * Affichage d'une liste de quad 
 */
void print_quad_list(list_quad* program) {
	while(program != NULL){
		print_quad(program->q);
		program = program->next;
	}
}

/*
 * Génère une instruction à 3 adresse et l'ajoute à la list_quad lq.
 * Incrémente aussi next_quad 
 */
quad* gen_code(list_quad** lq,int* nextquad,int op, symbol_table* arg1,symbol_table* arg2,symbol_table* res,int next) {
	quad* q = malloc(sizeof(quad));
	q->label = *nextquad;
	q->operateur = op;
	q->arg1 = arg1;
	q->arg2 = arg2;
	q->res = res;
	q->next = next;
	*nextquad = *nextquad + 1;
	if(*lq == NULL) {
		*lq = creer_list(q); 
		return q;
	}
	list_quad* courrant = *lq;
	while(courrant->next != NULL){courrant = courrant->next;};
	courrant->next = creer_list(q);
	return q;
}

